from django.shortcuts import render

# Create your views here.
"""
需求:     实现订单提交页面的展示功能

前端:     发送一个请求.请求cookie中携带 sessionid

后端:
        请求:
                    GET     /orders/settlement/     
        逻辑:
                1. 必须是登录用户
                2. 获取地址信息
                    2.1 查询用户 未删除的地址信息
                    2.2 将查询结果集转换为字典列表
                3. 获取购物车选中信息
                    3.1 连接redis
                    3.2 hash        {1:10,2:20}
                    3.3 set         {1}
                    3.4 查询选中商品的信息
                    3.5 将查询的对象数据转换为字典
                4. 运费
                5. 返回响应
        响应:
            "code": 0,
            "errmsg": "ok",
            "context": {
                "addresses": [
                    {
                        "id": 1,
                        "province": "北京市",
                        "city": "北京市",
                        "district": "顺义区",
                        "place": "京顺路99号",
                        "receiver": "itcast",
                        "mobile": "13312341234"
                    }
                ],
                "skus": [
                    {
                        "id": 14,
                        "name": "华为 HUAWEI P10 Plus 6GB+128GB 玫瑰金 移动联通电信4G手机 双卡双待",
                        "default_image_url": "http://qmllvum7m.hn-bkt.clouddn.com/CtM3BVrRdMSAaDUtAAVslh9vkK04466364.png",
                        "count": 1,
                        "price": "3788.00"
                    }
                ],
                "freight": 10
            }
"""
from django.views import View
from utils.user import LoginRequiredJSONMixin
from apps.users.models import Address
from django_redis import get_redis_connection
from apps.goods.models import SKU
from django.http import JsonResponse


class OrderSettlementView(LoginRequiredJSONMixin, View):
    def get(self, request):
        # 1. 必须是登录用户
        user = request.user
        # 2. 获取地址信息
        #     2.1 查询用户 未删除的地址信息
        addresses = Address.objects.filter(user=user, is_deleted=False)
        #     2.2 将查询结果集转换为字典列表
        addresses_list = []
        for address in addresses:
            addresses_list.append({
                'id': address.id,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'receiver': address.receiver,
                'mobile': address.mobile
            })
        # 3. 获取购物车选中信息
        #     3.1 连接redis
        redis_cli = get_redis_connection('carts')
        #     3.2 hash        {b'1':b'10',b'2':b'20'}
        sku_id_counts = redis_cli.hgetall('carts_%s' % user.id)
        #     3.3 set         {b'1'}
        selected_ids = redis_cli.smembers('selected_%s' % user.id)

        #     3.4 查询选中商品的信息 -- 我们就组织一个 字典.这个字典 只是 选中商品的信息 而且数据是 整型
        new_dict = {}  # new_dict = {sku_id:count}
        for id in selected_ids:
            new_dict[int(id)] = int(sku_id_counts[id])

        #     3.5 将查询的对象数据转换为字典
        skus_list = []
        for sku_id, count in new_dict.items():
            sku = SKU.objects.get(id=sku_id)
            skus_list.append({
                'id': sku.id,
                'name': sku.name,
                'price': int(sku.price),
                'count': count,
                'default_image_url': sku.default_image.url
            })
        # 4. 运费
        from decimal import Decimal
        # Decimal 货币类型
        # float double decimal
        #  100  /3 == 33.33
        # 33.33    33.33    33.34

        freight = 10
        # 5. 返回响应
        context = {
            'addresses': addresses_list,
            'skus': skus_list,
            'freight': freight
        }
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'context': context})


"""
需求:
        保存用户提交的 订单信息
前端:
        当用户点击保存订单的时候,前端发送ajax请求. 必须传递 地址id 支付方式.
        商品id, 数量 ,金额 都以后台为准
后端:

        请求:
                POST        /orders/commit/    body  JSON
        业务:
                必须是登录用户
                ①.接收数据
                ②.提取数据
                ③.验证数据
                ④.数据入库      
                    1.先保存订单基本信息
                        1.1 通过年月日时分秒来生成订单id
                        1.2 总数量和总金额 先记为 0 
                        1.3 运费
                        1.4 订单状态 -- 由支付方式决定
                    2.再保存订单商品信息
                        2.1 获取redis中的数据
                            hash
                            set
                        2.2 把数据整理一下 选中的字典 {sku_id:count}
                        2.3 遍历
                        2.4 根据商品id查询商品信息
                        2.5 判断商品库存.如果库存不足,下单失败
                        2.6 如果库存充足 应该让sku的销量增加,库存减少
                        2.7 统计总数量和总金额
                        2.8 保存订单商品信息
                    3.修改总数量和总金额
                ⑤.返回响应
        响应:
                code:0
"""

import json
from apps.order.models import OrderInfo, OrderGoods


class OrderCommitView(LoginRequiredJSONMixin, View):

    def post(self, request):
        # 必须是登录用户
        user = request.user
        # ①.接收数据
        data = json.loads(request.body.decode())
        # ②.提取数据
        address_id = data.get('address_id')
        pay_method = data.get('pay_method')
        # ③.验证数据
        try:
            address = Address.objects.get(id=address_id)
        except Address.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': '没有此地址'})

        # if pay_method not in [1,2]:       提高代码可读性
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return JsonResponse({'code': 400, 'errmsg': '支付方式错误'})
        # TODO ④.数据入库
        #    TODO 1.先保存订单基本信息
        # datetime 'YYYY-mm-dd HH:MM:SS '
        #      TODO 1.1 通过年月日时分秒来生成订单id
        from datetime import datetime

        # TODO Y: Year m: month d: day H: Hour M: Minute S: Second f: 微秒
        from django.utils import timezone
        order_id = timezone.now().strftime('%Y%m%d%H%M%S%f') + '%09d' % user.id
        #       TODO 1.2 总数量和总金额 先记为 0
        total_count = 0
        from decimal import Decimal
        total_amount = Decimal('0')
        #       TODO 1.3 运费
        freight = Decimal('10')
        #       TODO 1.4 订单状态 -- 由支付方式决定
        if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:  # 现金
            # 应该发货
            status = OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        else:
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']

        from django.db import transaction

        with transaction.atomic():

            # 一. 事务开始点
            start_point = transaction.savepoint()

            order = OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=address,
                total_count=total_count,
                total_amount=total_amount,
                freight=freight,
                pay_method=pay_method,
                status=status
            )
            # TODO 2.再保存订单商品信息
            redis_cli = get_redis_connection('carts')
            # TODO     2.1 获取redis中的数据
            # TODO         hash
            sku_id_counts = redis_cli.hgetall('carts_%s' % user.id)
            # TODO         set
            select_ids = redis_cli.smembers('selected_%s' % user.id)
            # TODO   2.2 把数据整理一下 选中的字典 {sku_id:count}
            new_selected_carts = {}
            for id in select_ids:
                new_selected_carts[int(id)] = int(sku_id_counts[id])
            #  2.3 遍历
            for sku_id, cart_count in new_selected_carts.items():
                # 2.4 根据商品id查询商品信息
                sku = SKU.objects.get(id=sku_id)
                #         2.5 判断商品库存.如果库存不足,下单失败
                if cart_count > sku.stock:
                    # 二. 事务的回滚
                    transaction.savepoint_rollback(start_point)
                    return JsonResponse({'code': 400, 'errmsg': '库存不足,请稍后再试'})

                from time import sleep
                sleep(7)
                #     2.6 如果库存充足 应该让sku的销量增加,库存减少
                # sku.stock -= cart_count
                # sku.sales += cart_count
                # sku.save()

                # TODO 1.记录之前的值
                old_stock = sku.stock  # 10

                new_stock = sku.stock - cart_count
                new_sales = sku.sales + cart_count
                # TODO 2.更新前,判断记录的值
                # 如果更新成功 result=1
                # 如果没有成功 result=0
                result = SKU.objects.filter(id=sku_id, stock=old_stock).update(stock=new_stock, sales=new_sales)
                if result == 0:
                    transaction.savepoint_rollback(start_point)
                    return JsonResponse({'code': 400, 'errmsg': '库存不足,下单失败'})

                #     2.7 统计总数量和总金额
                order.total_count += cart_count
                order.total_amount += (cart_count * sku.price)
                #     2.8 保存订单商品信息
                OrderGoods.objects.create(
                    order=order,
                    sku=sku,
                    count=cart_count,
                    price=sku.price
                )
                # 3.修改总数量和总金额
                order.save()

            # 三. 事务提交
            transaction.savepoint_commit(start_point)
        # 4. 把购物车中 选中的信息 删除

        # hash
        # dict = {key: value} --> **dict
        # selected_ids=[1,2,3,4,5]
        redis_cli.hdel('carts_%s' % user.id, *select_ids)
        # set
        redis_cli.srem('selected_%s' % user.id, *select_ids)

        # ⑤.返回响应
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'order_id': order_id})
